package demo.dcs.util;

import io.netty.channel.pool.FixedChannelPool;
import org.apache.commons.lang.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;

/**
 * Created by buffoon.wei on 15/10/13.
 */
public class XdcsGenericObjectPoolReflectUtil {

    private static final Logger logger = LoggerFactory.getLogger(XdcsGenericObjectPoolReflectUtil.class);

    /**
     * 反射拿object pool是否close的值
     * @param pool
     * @return
     */
    public static boolean isPoolClosed(Object pool){
        if (pool==null){
            return true;
        }

        Boolean isClosed = null;
        if (XdcsBeanUtils.isClassExist("org.apache.commons.pool2.impl.GenericObjectPool") && pool instanceof org.apache.commons.pool2.impl.GenericObjectPool){//2.6.0
            try {
                Field isCloseField = GenericObjectPool2FieldsCache.getInstance().getIsClosedFiled();
                isClosed = (Boolean)isCloseField.get(pool);
            } catch (Throwable e) {
                logger.error("get org.apache.commons.pool2.impl.GenericObjectPool isCloseField error", e);
            }
        }

        if (XdcsBeanUtils.isClassExist("org.apache.commons.pool.impl.GenericObjectPool") && pool instanceof org.apache.commons.pool.impl.GenericObjectPool){//2.1.0
            try {
                Field isCloseField = GenericObjectPoolFieldsCache.getInstance().getIsClosedFiled();
                isClosed = (Boolean)isCloseField.get(pool);
            } catch (Throwable e1) {
                logger.error("get org.apache.commons.pool.impl.GenericObjectPool isCloseField error", e1);
            }
        }

        return isClosed==null?true:isClosed;
    }


    /**
     * 反射拿netty object pool是否close的值
     * @param pool
     * @return
     */
    public static boolean isNettyPoolClosed(Object pool){
        if (pool==null){
            return true;
        }

        Boolean isClosed = null;
        if (XdcsBeanUtils.isClassExist("io.netty.channel.pool.FixedChannelPool") && pool instanceof FixedChannelPool){//netty pool
            try {
                Field isCloseField = FieldUtils.getField(FixedChannelPool.class, "closed", true);
                isClosed = (Boolean)isCloseField.get(pool);
            } catch (Throwable e1) {
                logger.error("get org.apache.commons.pool.impl.GenericObjectPool isCloseField error", e1);
            }
        }

        return isClosed==null?true:isClosed;
    }

    /**
     * 低版本commons-pool里的GenericObjectPool
     */
    private static class GenericObjectPoolFieldsCache {
        private static GenericObjectPoolFieldsCache instance;
        private final Field isClosedFiled;

        private GenericObjectPoolFieldsCache() throws Exception {
            isClosedFiled = org.apache.commons.pool.impl.GenericObjectPool.class.getSuperclass().getDeclaredField("closed");
            isClosedFiled.setAccessible(true);
        }

        public static GenericObjectPoolFieldsCache getInstance()throws Exception {

            if (instance == null) {
                synchronized (GenericObjectPoolFieldsCache.class) {
                    if (instance == null) {
                        instance = new GenericObjectPoolFieldsCache();
                    }
                }
            }
            return instance;
        }

        public Field getIsClosedFiled() {
            return isClosedFiled;
        }
    }


    /**
     * 高版本commons-pool里的GenericObjectPool
     */
    private static class GenericObjectPool2FieldsCache {
        private static GenericObjectPool2FieldsCache instance;
        private final Field isClosedFiled;

        private GenericObjectPool2FieldsCache() throws Exception {
            isClosedFiled = org.apache.commons.pool2.impl.GenericObjectPool.class.getSuperclass().getDeclaredField("closed");
            isClosedFiled.setAccessible(true);
        }

        public static GenericObjectPool2FieldsCache getInstance()throws Exception {

            if (instance == null) {
                synchronized (GenericObjectPool2FieldsCache.class) {
                    if (instance == null) {
                        instance = new GenericObjectPool2FieldsCache();
                    }
                }
            }
            return instance;
        }

        public Field getIsClosedFiled() {
            return isClosedFiled;
        }
    }
}
